package ca.concordia.soen6461.wichf.controller.dsl;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import ca.concordia.soen6461.wichf.controller.Action;
import ca.concordia.soen6461.wichf.controller.Condition;
import ca.concordia.soen6461.wichf.controller.Event;
import ca.concordia.soen6461.wichf.controller.View;

public class NavigationModelBuilderImpl implements NavigationModelBuilder {
	
	private class NavigationModelImpl implements NavigationModel {

		private ViewNode<?> homeViewNode;
		private Map<View<?>, ViewNode<?>> views = new HashMap<View<?>, ViewNode<?>>();
		
		public NavigationModelImpl() {
		}
		
		public ViewNode<?> getHomeViewNode() {
			return homeViewNode;
		}
		
		@SuppressWarnings("unchecked")
		public <V> ViewNode<V> getViewNode(View<V> view) {
			return (ViewNode<V>) views.get(view);
		}
		
	}
	
	private NavigationModelImpl navigationModel;

	public NavigationModelBuilderImpl(View<?> homeView) {
		navigationModel = new NavigationModelImpl();
		navigationModel.homeViewNode = addView(homeView);
	}

	private class NavigationEdgeBuilder implements OnEvent {

		private Class<? extends Event> event;
		private Condition condition = Condition.TRUE;
		private Action action = Action.NO_ACTION;
		
		private NavigationEdge newEdge(Navigation navigation) {
			NavigationEdge result = new NavigationEdge();
			result.setEvent(event);
			result.setCondition(condition);
			result.setAction(action);
			result.setNavigation(navigation);
			return result;
		}

		public NavigationEdgeBuilder(Class<? extends Event> event) {
			this.event = event;
		}
		
		@Override
		public ProvidedCondition provided(Condition condition) {
			this.condition = condition;
			return this;
		}
		
		@Override
		public PerformAction perform(Action action) {
			this.action = action;
			return this;
		}

		@Override
		public <V> NavigationEdge goTo(View<V> view) {
			return newEdge(new NavGoTo<V>(view));
		}

		@Override
		public NavigationEdge stay() {
			return newEdge(Navigation.STAY);
		}

		@Override
		public NavigationEdge goBack() {
			return newEdge(Navigation.BACK);
		}

		@Override
		public NavigationEdge goHome() {
			return newEdge(Navigation.HOME);
		}

	}
	
	public View<?> homeView() {
		return navigationModel.homeViewNode.getView();
	}
	
	private <V> ViewNode<V> addView(View<V> view) {
		ViewNode<V> node = navigationModel.getViewNode(view);
		if (node == null) {
			node = new ViewNode<V>(view);
			navigationModel.views.put(view, node);
		}
		return node;
	}
	
	public <V> void from(View<V> view, NavigationEdge... edges) {
		ViewNode<V> viewNode = addView(view);
		viewNode.getNavigationEdges().addAll(Arrays.asList(edges));
	}
	
	public OnEvent on(Class<? extends Event> event) {
		return new NavigationEdgeBuilder(event);
	}
	
	public NavigationModel getResult() {
		return navigationModel;
	}
	
}
